<template>
  <div :style="{backgroundColor: backgroundColor}" class="phone-header">
    <a-typography-title :level="4" class="title">
      软电话
    </a-typography-title>

    <!-- 操作控件 -->
    <a-space size="middle" class="controls">
      <!-- 登录操作 -->

      <a-button type="primary" shape="circle" size="middle" @click="toggleLogin" :loading="isLoginLoading">
        <template #icon v-if="loginValue === '1'">
          <a-tooltip title="登录">
            <LoginOutlined/>
          </a-tooltip>

        </template>
        <template #icon v-else>
          <a-tooltip title="登出">
            <LogoutOutlined/>
          </a-tooltip>

        </template>
      </a-button>

      <!-- 签入签出操作 -->
      <a-select
          v-model:value="signInOutValue"
          @change="handleSignInOutChange"
          :disabled="isSignInDisabled"
      >
        <a-select-option value='1'>签入</a-select-option>
        <a-select-option value='2'>签出</a-select-option>
      </a-select>
      <a-flex justify="center">
        <a-select v-model:value="agentStatusValue" size="large" :disabled="isAgentStatusDisabled">
          <a-select-option
              v-for="key in Object.keys(agentStatusMap) as []"
              :key="key"
              :value="key"
          >
            <span :style="{ color: agentStatusMap[key].color }">
              {{ agentStatusMap[key].label }}
            </span>
          </a-select-option>
        </a-select>
      </a-flex>

      <!--状态时长-->
      <a-flex>
        <a-tooltip title="状态时长">
          <a-typography-text strong>
            {{ statusDuration }}
          </a-typography-text>
        </a-tooltip>
      </a-flex>

      <!--键盘-->
      <a-flex>
        <a-input placeholder="请输入号码" allow-clear :value="phoneNumber" @input="handlePhoneNumberChange">
          <template #suffix>
            <a-button type="text" size="middle" @click="toggleKeypad">
              <NumberOutlined/>
            </a-button>
          </template>
        </a-input>
      </a-flex>

      <!--通话控制-->
      <a-tooltip title="挂断">
        <a-button type="primary" shape="circle" size="middle" @click="handleHangup">
          <template #icon>
            <PoweroffOutlined/>
          </template>
        </a-button>
      </a-tooltip>
      <a-tooltip :title="isHoldText">
        <a-button type="primary" shape="circle" size="middle" @click="handleHold">
          <template #icon v-if="isHold === '1'">
            <PauseCircleOutlined/>
          </template>
          <template #icon v-else>
            <PlayCircleOutlined/>
          </template>
        </a-button>
      </a-tooltip>

      <a-tooltip :title="isMuteText">
        <a-button type="primary" shape="circle" size="middle" @click="handleMute">
          <template #icon v-if="isMute === '1'">
            <AudioOutlined/>
          </template>
          <template #icon v-else>
            <AudioMutedOutlined/>
          </template>
        </a-button>
      </a-tooltip>

      <a-tooltip title="转接">
        <a-button type="primary" shape="circle" size="middle" @click="handleTransfer">
          <template #icon>
            <UserSwitchOutlined/>
          </template>
        </a-button>
      </a-tooltip>

      <a-tooltip title="自动应答">
        <a-switch checked-children="开" un-checked-children="关" v-model:checked="isAutoAnswer" @change="handleAutoAnswer" />
      </a-tooltip>
    </a-space>

    <a-flex vertical style="margin-left: auto">
      <!-- 注册状态 -->
      <span>
        <a-typography-text strong>
          注册状态:
        </a-typography-text>
        <a-typography-text :style="{ color: registerStatusColor}">
          {{ registerStatusText }}
        </a-typography-text>
      </span>
      <!-- 网络状态 -->
      <span>
        <a-typography-text strong>
          网络状态:
        </a-typography-text>
        <WifiOutlined :style="{ color: networkStatusColor,  fontSize: '20px',marginLeft: '8px'}"/>
      </span>
    </a-flex>
  </div>
  <!-- 拨号键盘 -->
  <a-card v-if="isKeypadVisible" class="dialpad" bordered>
    <!-- 数字键 -->
    <div class="dialpad-grid">
      <template v-for="row in dialpadRows" :key="row.join('')">
        <template v-for="num in row" :key="num">
          <a-button @click="handleDialInput(num)" class="dialpad-button">
            {{ num }}
          </a-button>
        </template>
      </template>
    </div>
    <a-button type="primary" block class="dialpad-call" @click="makeCall">
      <template #icon>
        <PhoneOutlined/>
        拨打
      </template>
    </a-button>
  </a-card>
  <a-modal v-model:open="incomingCallFlag" title="来电">
    <template #footer>
      <a-button key="back"  @click="handleHangup">挂断</a-button>
      <a-button key="submit" type="primary" @click="handleAnswer">接听</a-button>
    </template>
    <p>来电号码：{{ incomingCallNumber }}</p>
  </a-modal>
</template>

<script setup lang="ts">
import {computed, onBeforeUnmount, onMounted, ref, watch} from 'vue';
import {
  AudioMutedOutlined,
  AudioOutlined,
  LoginOutlined,
  LogoutOutlined,
  NumberOutlined,
  PauseCircleOutlined,
  PhoneOutlined,
  PlayCircleOutlined,
  PoweroffOutlined,
  UserSwitchOutlined,
  WifiOutlined
} from '@ant-design/icons-vue'
import JsSIP from 'jssip';
import ringing from '@/assets/ringing.wav'
import { message } from 'ant-design-vue';
import {updateAgentStatus} from "./WebSocketClient"
// 状态变量
const backgroundColor = ref<string>('#f5f5f5');
const loginValue = ref<string>('1');
const signInOutValue = ref<string>('2');
const agentStatusValue = ref<string>('4');
const isLoginLoading = ref<boolean>(false);
const isSignInDisabled = ref<boolean>(true);
const statusDuration = ref<string>('00:00:00');
const callTimer = ref<any>(null);
const isKeypadVisible = ref<boolean>(false);
const phoneNumber = ref<string>('');
const isHold = ref<string>('1');
const isMute = ref<string>('1');
const isAutoAnswer = ref<boolean>(false);
const incomingCallFlag = ref<boolean>(false);
const incomingCallNumber = ref<string>('');

const agentStatusMap: Record<string, any> = {
  '1': {label: '空闲', color: '#52c41a'},
  '2': {label: '忙碌', color: '#faad14'},
  '3': {label: '勿扰', color: '#ff4d4f'},
  '4': {label: '离线', color: '#8c8c8c'},
  '5': {label: '通话中', color: '#c4eab0'},
  '6': {label: '振铃中', color: '#d29289'},
  '7': {label: '话后', color: '#7a0d17'},
}
const dialpadRows = [
  ['1', '2', '3'],
  ['4', '5', '6'],
  ['7', '8', '9'],
  ['*', '0', '#']
];
const sipConfig = reactive({
  socket: {
    ws_servers: 'wss://localhost:5443',
    sip_host: 'localhost:5180',
    sip_user: '1001',
    password: '1234',
    register: false,
    no_answer_timeout: 60,
  },
})
let ua: JsSIP.UA;
let currentSession = ref<any>(null);
let audioView = new Audio; //audio标签

const isHoldText = computed(() => {
  return {
    '1': '保持',
    '2': '取消保持'
  }[isHold.value];
});
const isMuteText = computed(() => {
  return {
    '1': '静音',
    '2': '取消静音'
  }[isMute.value];
});
// 注册状态管理
const registerStatus = ref<'unregistered' | 'registered' | 'error'>('unregistered');
const registerStatusText = computed(() => {
  return {
    unregistered: '未注册',
    registered: '已注册',
    error: '失败'
  }[registerStatus.value];
});
const registerStatusColor = computed(() => {
  return {
    unregistered: '#e10e10',
    registered: '#52c41a',
    error: '#faad14'
  }[registerStatus.value];
});

const isAgentStatusDisabled = computed(() => {
  return {
    '1': false,
    '2': true
  }[signInOutValue.value]
})

watch(agentStatusValue, (value) => {
  handleAgentStatusChange(value);
})

// 网络状态管理
const networkStatus = ref<'connected' | 'disconnected' | 'connecting'>('disconnected');
const networkStatusColor = computed(() => {
  return {
    connected: '#52c41a',
    disconnected: '#ff4d4f',
    connecting: '#1677ff'
  }[networkStatus.value];
});
const ringAudio = new Audio(ringing)

/**
 * 处理坐席状态变化
 * @param value
 */
const handleAgentStatusChange = (value: string) => {
  computeStatusDuration();
  console.log('坐席状态：', agentStatusMap[value].label);
  updateAgentStatus(8,value);
}


//登录登出
const toggleLogin = async () => {
  if (loginValue.value === '1') {
    console.log('登录');
    loginValue.value = '2';
    isLoginLoading.value = true;
    isSignInDisabled.value = false;
    backgroundColor.value = '#e6f7ff';
    computeStatusDuration();
    // 初始化SIP客户端
    initSipClient();

    isLoginLoading.value = false;
  } else if (loginValue.value === '2') {
    console.log('退出');
    loginValue.value = '1';
    isLoginLoading.value = true;
    signInOutValue.value = '2';
    isSignInDisabled.value = true;
    backgroundColor.value = '#f5f5f5';
    clearCallTimer();
    // 注销SIP客户端
    unregisterSipClient();
    isLoginLoading.value = false;
  }
}


// 处理签入签出变化
const handleSignInOutChange = (value: string) => {
  if (value === '1') {
    console.log('签入');
    agentStatusValue.value = '1';
    if (ua) {
      ua.register();
    }
  } else if (value === '2') {
    console.log('签出');
    agentStatusValue.value = '4';
    if (ua) {
      ua.unregister();
    }
  }
};

//检查网络状态
const checkNetworkStatus = () => {
  if (navigator.onLine) {
    networkStatus.value = 'connected';
  } else {
    networkStatus.value = 'disconnected';
  }
};

//取消状态定时器
const clearCallTimer = () => {
  if (callTimer.value) {
    clearInterval(callTimer.value);
    statusDuration.value = '00:00:00';
  }
}

//状态时长计时
const computeStatusDuration = () => {
  if (callTimer.value) {
    statusDuration.value = '00:00:00';
    clearInterval(callTimer.value);
  }
  let startTime = new Date();
  callTimer.value = setInterval(() => {
    //statusDuration开始计时
    const now = new Date();
    const diff = now.getTime() - startTime.getTime();
    // 计算时分秒
    const hours = Math.floor(diff / 3600000)
        .toString()
        .padStart(2, '0');
    const minutes = Math.floor((diff % 3600000) / 60000)
        .toString()
        .padStart(2, '0');
    const seconds = Math.floor((diff % 60000) / 1000)
        .toString()
        .padStart(2, '0');
    statusDuration.value = `${hours}:${minutes}:${seconds}`;
  }, 1000);

}

//弹出卡片键盘
const toggleKeypad = () => {
  isKeypadVisible.value = !isKeypadVisible.value;
}

//拨号键盘事件
const handleDialInput = (digit: string) => {
  phoneNumber.value += digit;
};

//拨号键盘删除事件
const handleDelete = () => {
  phoneNumber.value = phoneNumber.value.slice(0, -1);
};

//号码输入框变更事件
const handlePhoneNumberChange = (e: InputEvent) => {
  const input = (e.target as HTMLInputElement).value;
  const oldVal = phoneNumber.value;
  // 防止非法字符输入
  const sanitizedInput = input.replace(/[^0-9*#]/g, '');
  // 当输入为空时，直接清空号码
  if (sanitizedInput === '') {
    phoneNumber.value = '';
    return;
  }
  if (sanitizedInput.length > oldVal.length) {
    // 用户输入了字符
    const addedChar = sanitizedInput.slice(-1);
    handleDialInput(addedChar);
  } else if (sanitizedInput.length < oldVal.length) {
    // 用户删除了字符
    handleDelete();
  }
};

//网络状态变化事件
const handleOnline = () => {
  networkStatus.value = 'connected';
  console.log('网络已连接');
};

//网络状态变化事件
const handleOffline = () => {
  networkStatus.value = 'disconnected';
  console.log('网络已断开');
  alert('网络连接已断开，请检查您的网络');
};

const initSipClient = async () => {
  console.log('初始化SIP客户端');
  const { ip: publicIP, port: publicPort } = await getPublicIPAndPort();
  console.log('发现公网地址：', publicIP, publicPort);
  const socket = new JsSIP.WebSocketInterface(sipConfig.socket.ws_servers);
  JsSIP.C.SESSION_EXPIRES = 3600;
  //JSSIP调试开关
  //JsSIP.debug.enable('JsSIP:*');
  let uri = `sip:${sipConfig.socket.sip_user}@${sipConfig.socket.sip_host}`;
  let configuration = {
    sockets: [socket],
    uri: uri,
    contact_uri: `sip:${sipConfig.socket.sip_user}@${publicIP}:${publicPort};transport=ws`,
    password: sipConfig.socket.password,
    register: false,
    no_answer_timeout: 60,
  };
  ua = new JsSIP.UA(configuration);
  registerSipEvents();
  ua.start();
}

//注销客户端
const unregisterSipClient = () => {
  console.log('注销SIP客户端');
  if (!ua) {
    console.warn('SIP客户端未初始化');
    return;
  }
  try {
    if (ua.isConnected()) {
      ua.stop();
      console.log('SIP登出成功');
    }
  } catch (error) {
    console.error('SIP登出失败:', error);
  }
}

//注册SIP事件
const registerSipEvents = () => {
  ua.on('registered', () => {
    console.log('SIP注册成功');
    registerStatus.value = 'registered';
    backgroundColor.value = '#c5e7b5';
    computeStatusDuration();
  });

  ua.on('unregistered', () => {
    console.log('SIP注销成功');
    registerStatus.value = 'unregistered';
    backgroundColor.value = '#e6f7ff';
    clearCallTimer();
  });

  ua.on('registrationFailed', (response) => {
    console.error('SIP注册失败:', response);
    registerStatus.value = 'error';
  });

  ua.on('newRTCSession', (data: any) => {
    const session = data.session;
    currentSession.value = session;
    if (data.originator == "local") {
      currentSession.value.connection.addEventListener('track', (event: any) => {
        audioView.srcObject = event.streams[0];
        audioView.play();
        audioView.volume = 1;
      });
    }
    // 处理来电
    if (data.originator === 'remote') {
      incomingCallFlag.value = true;
      incomingCallNumber.value = session.remote_identity.uri.user;
      phoneNumber.value = incomingCallNumber.value;
      // 处理新的会话事件
      session.on('connecting', (e: any) => {
        console.log('呼入会话连接中...', e);
      });

      session.on('progress', (e: any) => {
        console.log('呼入会话进度更新: 振铃中', e);
        agentStatusValue.value = '6';
        if(isAutoAnswer.value){
          handleAnswer()
        }else {
          //播放振铃录音
          ringAudio.loop = true;
          ringAudio.play().catch(err => {
            console.error('播放振铃录音失败:', err);
          });
        }
      });

      session.on('failed', (e: any) => {
        console.error('呼入会话失败:', e);
        // 重置通话状态
      });

      session.on('ended', (e: any) => {
        console.log('呼入会话结束', e);
        agentStatusValue.value = '7';
        // 重置通话状态
      });

      session.on('confirmed', (e: any) => {
        console.log('呼入会话确认: 通话中', e);
        // 开始计时通话时长
      });
      session.on('muted', (e: any) => {
        console.log('呼入通话静音:', e);
      });
      session.on('unmuted', (e: any) => {
        console.log('呼入通话取消静音:', e);
      })
      session.on('sdp', (e: any) => {
        console.log('呼入通话sdp:', e);
      })
    }
  });
};


const makeCall = () => {
  if (!phoneNumber.value) {
    alert('请输入要拨打的号码');
    return;
  }

  if (!ua || !ua.isRegistered()) {
    alert('请先登录SIP账号');
    return;
  }
  const eventHandlers = {
    connecting: (e: any) => {
      console.log('拨打会话连接中...:', e);
    },
    progress: (e: any) => {
      console.log('拨打会话进度更新: 振铃中:', e);
    },
    failed: (e: any) => {
      console.log('拨打呼叫失败:', e);
    },
    ended: (e: any) => {
      console.log('拨打会话结束:', e);
    },
    confirmed: (e: any) => {
      console.log('拨打会话确认: 通话中:', e);
    },
    muted: (e: any) => {
      console.log('通话静音:', e);
    },
    unmuted: (e: any) => {
      console.log('通话取消静音:', e);
    }
  };
  const options = {
    mediaConstraints: {
      audio: true,
      video: false
    },
    eventHandlers,
    pcConfig: {
      iceServers: [
        {
          urls: "stun:stun.l.google.com:19302",
        },
      ],
    }
  };
  ua.call(`sip:${phoneNumber.value}@${sipConfig.socket.sip_host}`, options);
};

//接听
const handleAnswer = () => {
  if (currentSession.value) {
    // 接听通话
    currentSession.value.answer({
      mediaConstraints: {audio: true, video: false},
      pcConfig: {
        iceServers: [
          {
            urls: "stun:stun.l.google.com:19302",
          },
        ],
      }
    });
    agentStatusValue.value = '5';
    ringAudio.pause();
    currentSession.value.connection.addEventListener('track', (event: any) => {
      console.log('收到呼叫的媒体流:', event);
      audioView.srcObject = event.streams[0];
      audioView.play();
      audioView.volume = 1;
    });
    // 开始计时通话时长
    computeStatusDuration();
  } else {
    message.warning('没有正在进行的通话');
  }
  incomingCallFlag.value = false;
};

//挂断
const handleHangup = () => {
  if (currentSession.value) {
    ringAudio.pause();
    // 终止当前通话
    currentSession.value.terminate();
    // 清理通话状态
    currentSession.value = null;
    agentStatusValue.value = '7';
    // 停止计时
    clearCallTimer();
    // 重置状态提示
    message.success('通话已挂断');
  } else {
    message.warning('没有正在进行的通话');
  }
  incomingCallFlag.value = false;
}

//暂停或恢复通话
const handleHold = () => {
  if (currentSession.value && isHold.value === '2') {
    // 恢复通话
    currentSession.value.unhold({useUpdate: false}, () => {
      message.success('取消保持')
      isHold.value = '1';
    });
  } else if (currentSession.value && isHold.value === '1') {
    // 暂停通话
    currentSession.value.hold({useUpdate: false}, () => {
      message.success('保持中')
      isHold.value = '2';
    });
  } else {
    message.warning('没有正在进行的通话');
  }
};

//静音或取消静音
const handleMute = () => {
  if (!currentSession.value) {
    message.warning('没有正在进行的通话');
    return;
  }
  if (isMute.value === '1') {
    // 静音
    currentSession.value.mute({audio: true, video: false});
    isMute.value = '2';
    message.success('已静音')
  } else if (isMute.value === '2') {
    //取消静音
    currentSession.value.unmute({audio: true, video: false});
    isMute.value = '1';
    message.success('已取消静音')
  }
};

const handleTransfer = () => {
  if (!currentSession.value) {
    message.warning('没有正在进行的通话');
    return;
  }
  const transferNumber = prompt('请输入转接号码:', '');
  if (transferNumber) {
    currentSession.value.refer(`sip:${transferNumber}@${sipConfig.socket.sip_host}`);
    console.log(`呼叫转接至: ${transferNumber}`);
  } else {
    message.warning('未输入目标号码，呼叫转接已取消');
  }
}

const handleAutoAnswer = () => {
  message.success(`自动接听已${isAutoAnswer.value ? '开启' : '关闭'}`);
};

//组件初始化
onMounted(() => {
  console.log('组件初始化');
  // 主动检查一次网络状态
  checkNetworkStatus();
  // 网络状态变化监听
  window.addEventListener('online', handleOnline);

  window.addEventListener('offline', handleOffline);
});

//组件卸载
onBeforeUnmount(() => {
  unregisterSipClient()
  // 移除网络状态监听器
  window.removeEventListener('online', handleOnline);
  window.removeEventListener('offline', handleOffline);
});


async function getPublicIPAndPort(stunServers = ['stun:stun.l.google.com:19302']) {

  return new Promise((resolve, reject) => {
    const pc = new RTCPeerConnection({
      iceServers: stunServers.map(url => ({ urls: url }))
    });

    // 必须创建一个 DataChannel 或音视频轨道以触发 ICE
    pc.createDataChannel('dummy');

    pc.onicecandidate = (evt) => {
      if (!evt.candidate) {
        // ICE gathering 完成
        pc.close();
        reject(new Error('未能获取到公网 ICE 候选'));
        return;
      }
      const parts = evt.candidate.candidate.split(' ') as Array<string>;
      const [ , , , , ip, port, , type ] = parts;
      // 只取 server‐reflexive (srflx) 或 relay 类型
      if ((type === 'srflx' || type === 'relay') && ip && port) {
        pc.close();
        resolve({ ip, port });
      }
    };

    pc.createOffer()
        .then(desc => pc.setLocalDescription(desc))
        .catch(err => {
          pc.close();
          reject(err);
        });
  });
}

</script>

<style lang="less" scoped>
.phone-header {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
  border-radius: 16px;
  transition: all 0.3s ease;
  position: relative;

  &:hover {
    transform: translateY(-3px);
    box-shadow: 0 8px 20px rgba(0, 0, 0, 0.16);
  }

  .title {
    margin: 0;
    padding-left: 12px;
    color: #1a1a1a;
    font-weight: 700;
    font-size: 20px;

    &:deep(.anticon-question-circle-o) {
      font-size: 14px;
    }
  }

  .controls {
    display: flex;
    flex-wrap: wrap;
    margin-left: 16px;
  }
}

.dialpad {
  width: 260px;
  margin-left: 371px;
  margin-top: 8px;
  transition: all 0.3s ease;
  animation: fadeIn 0.3s ease;
  position: relative; /* 确保 z-index 生效 */
  z-index: 1000; /* 设置较高的 z-index 值 */

  .dialpad-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    grid-gap: 8px; /* 调整按钮之间的间距 */
  }

  .dialpad-call {
    margin-top: 5px;
  }

  .dialpad-button {
    height: 48px;
    font-size: 18px;
    border-radius: 4px; /* 圆角效果 */

    &:hover {
      background-color: #f0f0f0; /* 鼠标悬停时的背景颜色 */
    }

    &:active {
      background-color: #e0e0e0; /* 点击时的背景颜色 */
    }
  }

  &:deep(.ant-card-body) {
    padding: 16px;
  }
}

@keyframes fadeIn {
  from {
    opacity: 0;
    transform: translateY(-10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}
</style>